import numpy as np
import pandas as pd
from collections import defaultdict
import random
from sklearn.preprocessing import LabelEncoder

# 模拟顾客购买行为数据集
data = {
    'Customer ID': [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010],
    'Item1': ['牛奶', '面包', '牛奶', '牛奶', '面包', '黄油', '牛奶', '黄油', '苹果', '面包'],
    'Item2': ['面包', '黄油', '果汁', '面包', '黄油', '苹果', '苹果', '面包', '饼干', '饼干'],
    'Item3': ['黄油', '苹果', '水果', '苹果', '饼干', '水果', '面包', '果汁', '果汁', '苹果'],
    'Amount': [20.5, 15.0, 18.0, 22.0, 12.5, 14.0, 19.0, 21.0, 16.0, 17.5]
}

# 转换为 DataFrame
df = pd.DataFrame(data)

# 显示原始数据集
print("原始数据集:")
print(df)

# 对类别变量进行编码
label_encoder = LabelEncoder()
df['Item1'] = label_encoder.fit_transform(df['Item1'])
df['Item2'] = label_encoder.fit_transform(df['Item2'])
df['Item3'] = label_encoder.fit_transform(df['Item3'])

# 显示编码后的数据
print("\n编码后的数据集:")
print(df)


# 定义 KMeans 类
class KMeans:
    def __init__(self, k, max_iters=100):
        self.k = k
        self.max_iters = max_iters

    def fit(self, X):
        # 初始化质心
        self.centroids = [X[random.randint(0, len(X) - 1)] for _ in range(self.k)]

        for _ in range(self.max_iters):
            # 步骤1：为每个点分配最近的质心
            clusters = defaultdict(list)
            for point in X:
                distances = [np.linalg.norm(point - centroid) for centroid in self.centroids]
                clusters[np.argmin(distances)].append(point)

            # 步骤2：更新质心
            new_centroids = []
            for i in range(self.k):
                if clusters[i]:
                    new_centroids.append(np.mean(clusters[i], axis=0))
                else:
                    new_centroids.append(self.centroids[i])

            # 如果质心不再变化，停止迭代
            if np.allclose(self.centroids, new_centroids):
                break
            self.centroids = new_centroids

        # 返回聚类结果
        self.clusters = clusters
        return self.clusters

    def predict(self, X):
        predictions = []
        for point in X:
            distances = [np.linalg.norm(point - centroid) for centroid in self.centroids]
            predictions.append(np.argmin(distances))
        return np.array(predictions)


# 获取数据集中的数值特征（商品编码和金额）
X = df[['Item1', 'Item2', 'Item3', 'Amount']].values

# 创建 KMeans 实例
kmeans = KMeans(k=2)

# 进行聚类
clusters = kmeans.fit(X)

# 打印聚类结果
print("\n聚类结果:")
for cluster_id, points in clusters.items():
    print(f"簇 {cluster_id}:")
    for point in points:
        # 找到点对应的顾客ID
        customer_id = df.iloc[np.where(np.all(X == point, axis=1))]['Customer ID'].values[0]
        print(f"  顾客ID: {customer_id}")
